package main

import (
	"flag"
	"os"
	"path"
	"strings"

	"xgame.go_server/cluster"
	"xgame.go_server/comm/log"
	"xgame.go_server/gateway_server/network/ws"
	"xgame.go_server/msg"
)

var pServerId *int             // 服务器 Id
var pBindHost *string          // 绑定主机地址
var pBindPort *int             // 绑定端口号
var pLogFile *string           // 日志文件
var pEtcdEndpointArray *string // ETCD 节点地址数组

// 初始化
func init() {
	ex, err := os.Executable()

	if nil != err {
		panic(err)
	}

	defultLogFile := path.Dir(ex) + "/log/gateway_server.log"

	pServerId = flag.Int("server_id", 0, "网关服务器 Id")
	pBindHost = flag.String("bind_host", "127.0.0.1", "绑定主机地址")
	pBindPort = flag.Int("bind_port", 54321, "绑定端口号")
	pLogFile = flag.String("log_file", defultLogFile, "日志文件")
	pEtcdEndpointArray = flag.String("etcd_endpoint_array", "127.0.0.1:2379", "Etcd 节点地址数组")
	flag.Parse()
}

// 应用程序主函数
func main() {
	// 配置日志
	log.Config(*pLogFile)

	// 启动服务器
	bootUp()
}

// 启动服务器
func bootUp() {
	log.Info(
		"启动网关服务, serverId = %d, serverAddr = %s:%d",
		*pServerId,
		*pBindHost,
		*pBindPort,
	)

	// 启动 WebSocket 服务器
	ws.StartServer(*pBindHost, *pBindPort, "/ws")

	ectdEndpointArray := strings.Split(*pEtcdEndpointArray, ",")

	cluster.StartDiscoverNewBizServer(ectdEndpointArray, func(serverData *cluster.BizServerData) {
		if nil == serverData ||
			nil == serverData.WsConn {
			return
		}

		go func() {
			defer func() {
				//
				// 退出函数之前从集群中删除数据
				log.Warning(
					"断开业务服务器连接, serverId = %d",
					serverData.ServerId,
				)

				cluster.Delete(serverData)
			}()

			for {
				//
				// 读取从游戏服返回来的消息，
				// 这个消息将回发给游戏客户端...
				_, msgData, err := serverData.WsConn.ReadMessage()

				if nil != err {
					// 遇到异常,
					// 则很有可能是业务服务器已经宕机...
					log.Error("%+v", err)
					break
				}

				innerCmd := &msg.InnerCmd{}
				innerCmd.FromByteArray(msgData)

				log.Info(
					"从业务服务器返回结果, sessionUId = %s, userId = %d",
					innerCmd.SessionUId,
					innerCmd.UserId,
				)

				//
				// 这个是客户端到网关服务器的上下文对象,
				// 通过它来发送消息给客户端...
				cmdCtx := ws.TheCmdCtxGroup().GetBySessionUId(innerCmd.SessionUId)

				if nil == cmdCtx {
					log.Error("未找到指令上下文")
					continue
				}

				if cmdCtx.GetUserId() <= 0 &&
					innerCmd.UserId > 0 {
					cmdCtx.BindUserId(innerCmd.UserId)
				}

				cmdCtx.Write(innerCmd.MsgData)
			}
		}()
	})

	// 阻塞程序, 使其不退出...
	syncWait := make(chan int16)
	<-syncWait
}
